home *** CD-ROM | disk | FTP | other *** search
- unit DOSInfo;
-
- interface
-
- uses WinTypes, WinProcs, WinDOS, Strings;
-
- function GetFloppyDriveCount: Integer;
- function GetFloppyDriveType (index: Integer): Integer;
- function GetDriveLabel (drive: Integer): String;
- function SetDriveLabel (drive: Integer; VolLabel: String): Integer;
- function GetSerialNumber (drive: Byte): LongInt;
- function SetSerialNumber (drive: Byte; serNum: LongInt): Bool;
- function GetCDDriveLetter: Char;
- function RunningFromCD: Bool;
-
- implementation
-
- type XFCB = record { prehistoric extended FCB - yuck }
- extSig: Byte; { must be $FF for extended flag }
- extRes: array [0..4] of Byte; { reserved stuff }
- extAttr: Byte; { file attribute }
- extDrive: Byte; { drive number }
- extFName: array [0..10] of Char; { filename }
- extJunk: array [0..24] of Byte; { rest of the junk is irrelevant }
- end;
-
- type
- PMIDINFO = ^MIDINFO;
- MIDINFO = record
- InfoLevel: Word;
- SerialNum: Longint;
- VolLabel: array[0..10] of Char;
- FileSystem: array [0..7] of Char;
- end;
-
- var
- R: record { Real mode call structure }
- di, si, bp, Reserved, bx, dx, cx, ax : Longint;
- Flags, es, ds, fs, gs, ip, sp, ss: Word;
- end;
-
- { Read a single byte from CMOS memory }
-
- function ReadCMOSByte (idx: Byte): Word; assembler;
- asm
- mov al,idx { get the wanted index }
- out 70h,al { write address into address reg }
- in al,71h { read the drive type into AL }
- mov ah,0 { clear the high byte }
- end;
-
- { Count the number of physical (not logical) floppy drives) }
-
- function GetFloppyDriveCount: Integer;
- var
- regs: TRegisters;
- begin
- { Get equipment bits }
- FillChar (regs, sizeof (regs), 0);
- Intr ($11, regs);
- if (regs.AX and 1) = 0 then GetFloppyDriveCount := 0 else
- GetFloppyDriveCount := ((regs.AX and $C0) shr 6) + 1;
- end;
-
- { Return the type (max KB capacity) of a given floppy drive }
-
- function GetFloppyDriveType (index: Integer): Integer;
- var
- flopFlags: Word;
-
- function FlagsToKBytes (flags: Word): Integer;
- begin
- case flags of
- 0: FlagsToKBytes := 0;
- 1: FlagsToKBytes := 360;
- 2: FlagsToKBytes := 1200;
- 3: FlagsToKBytes := 720;
- 4: FlagsToKBytes := 1440;
- 5: FlagsToKBytes := 2880;
- else FlagsToKBytes := -1;
- end
- end;
-
- begin
- flopFlags := ReadCMOSByte ($10);
- case index of
- 0: GetFloppyDriveType := FlagsToKBytes (flopFlags shr 4);
- 1: GetFloppyDriveType := FlagsToKBytes (flopFlags and 15);
- else GetFloppyDriveType := 0;
- end;
- end;
-
- { Return the drive label of a specified drive }
-
- function GetDriveLabel (drive: Integer): String;
- var
- i: Integer;
- s: String;
- rec: WinDOS.TSearchRec;
- path: array [0..10] of Char;
- begin
- s := '';
- lstrcpy (path, 'X:\*.*');
- path [0] := Chr (drive + $40); { 1=A, 2=B, etc... }
- WinDOS.FindFirst (path, 8, rec);
- if WinDOS.DOSError = 0 then
- begin
- for i := 0 to 12 do
- if rec.Name [i] = #0 then break
- else if rec.Name [i] <> '.' then s := s + rec.Name [i];
- end;
-
- GetDriveLabel := s;
- end;
-
- { Initialise 'fcb' for volume label twiddling - bleurgh ! }
-
- procedure InitLabelFCB (drive: Byte; var fcb: XFCB);
- begin
- FillChar (fcb, sizeof (fcb), 0);
- with fcb do
- begin
- extSig := $ff; { mark FCB as extended }
- extAttr := 8; { specify VOLUME attribute }
- extDrive := drive; { set up drive number (1=A, 2=B..) }
- FillChar (extFName, sizeof (extFName), '?');
- end;
- end;
-
- { Trash any existing volume label }
-
- function NukeVolumeLabel (drive: Byte): Integer;
- var
- fcb: XFCB;
- regs: TRegisters;
- begin
- FillChar (regs, sizeof (regs), 0);
- InitLabelFCB (drive, fcb);
- regs.ah := $13;
- regs.dx := Ofs (fcb);
- regs.ds := Seg (fcb);
- MSDos (regs);
- NukeVolumeLabel := regs.al;
- end;
-
- { This routine massages a user-supplied volume label. It is rejected if
- any invalid characters are supplied, alpha's are uppercased, and it's
- converted into 8.3 format preceeded by 'X:\'. }
-
- function MassageVolumeLabel (VolLabel: String): String;
- var
- i: Integer;
- str: String;
- begin
- str := '';
- MassageVolumeLabel := '';
- { Validate the user input }
- if Length (VolLabel) > 11 then VolLabel [0] := Chr (11);
- for i := 1 to Length (VolLabel) do
- begin
- if StrScan ('*?/\|.,;:+=[]()&^<>"', VolLabel [i]) <> Nil then Exit;
- if Length (str) = 8 then str := str + '.';
- str := str + UpCase (VolLabel [i]);
- end;
-
- MassageVolumeLabel := 'X:\' + str;
- end;
-
- { create a volume label - assumes there's not one already there }
-
- function CreateVolLabel (drive: Byte; volName: String): Integer;
- var
- i: Integer;
- regs: TRegisters;
- path: array [0..20] of Char;
-
- begin
- CreateVolLabel := -1;
- StrPCopy (path, MassageVolumeLabel (volName));
- if path [0] = #0 then Exit; { label was invalid }
- path [0] := Chr (drive + $40); { 1=A, 2=B, etc... }
-
- FillChar (regs, sizeof (regs), 0); { safe p-mode programming... }
- regs.ah := $3C; { specify create file }
- regs.cx := 8; { set volume label attribute }
- regs.dx := Ofs (path); { set up pointer to name }
- regs.ds := Seg (path); { DS:DS is the pointer pair }
- MSDos (regs); { do the business... }
-
- if not (Odd (regs.Flags)) then { if no carry, then ok }
- begin
- _lclose (regs.ax);
- CreateVolLabel := 0;
- end;
- end;
-
- { Higher-level volume settings code. Takes care of replacing,
- nuking, etc. }
-
- function SetDriveLabel (drive: Integer; VolLabel: String): Integer;
- var
- err: Integer;
- OldLabel: String;
- begin
- err := 0;
- OldLabel := GetDriveLabel (drive);
-
- { If old and new labels are the same, nothing to do }
- if OldLabel <> VolLabel then
- begin
- { If got an old label, then delete it }
- if OldLabel <> '' then err := NukeVolumeLabel (drive);
- { If we've got a new label, then set it up }
- if (err = 0) and (VolLabel <> '') then err := CreateVolLabel (drive, volLabel);
- end;
-
- SetDriveLabel := err;
- end;
-
- {----------------------------------------------------------------------------}
- { Name: GetSetMid }
- { Purpose: Low level code to get or set a MIDINFO data structure for the }
- { specified drive. RealModeAX = $6900 for a get and $6901 for a }
- { set operation. }
- {----------------------------------------------------------------------------}
-
- function GetSetMid (Drive: Byte; MID: PMIDINFO; RealModeAX: Word): Bool;
- var
- Error: Byte;
- begin
- { Assume everything ok }
-
- Error := 0;
- GetSetMid := True;
-
- R.ax := RealModeAX;
- R.bx := Drive;
- R.ds := HiWord (Longint (MID)); { Subtle !!! }
- R.dx := LoWord (Longint (MID));
-
- asm
- mov bx, 0021h { set flags to $00, Real mode interrupt $21 }
- xor cx, cx { copy 0 words from protected mode stack }
- mov ax, seg R
- mov es, ax { selector of real mode call structure }
- mov di, offset R { offset of real mode call structure }
- mov ax, 0300h { DPMI simulate real mode interrupt }
- int 31h { do the business }
- jnc @@1 { branch if no error }
- inc Error
- @@1:
- end;
-
- if Error = 1 then GetSetMid := False;
- end;
-
- {----------------------------------------------------------------------------}
- { Name: GetMid }
- { Purpose: Get the MIDINFO record for a specified drive. }
- { Uses GetSetMid. Returns TRUE if successful. }
- {----------------------------------------------------------------------------}
-
- function GetMid (drive: Byte; var mid: MIDINFO): Bool;
- var
- p: LongInt;
- begin
- { Assume failure }
- GetMid := False;
-
- { Allocate a MIDINFO data structure in DOS address-space }
- p := GlobalDOSAlloc (sizeof (MIDINFO));
-
- if GetSetMid (drive, Ptr (HiWord (p), 0), $6900) then
- begin
- mid := PMIDINFO (Ptr (LoWord (p), 0))^;
- GetMid := True;
- end;
-
- GlobalDOSFree (LoWord (p));
- end;
-
- {----------------------------------------------------------------------------}
- { Name: SetMid }
- { Purpose: Set the MIDINFO record for a specified drive. }
- { Uses GetSetMid. Returns TRUE if successful. }
- {----------------------------------------------------------------------------}
-
- function SetMid (drive: Byte; var mid: MIDINFO): Bool;
- var
- p: LongInt;
- begin
- { Assume failure }
- SetMid := False;
-
- { Allocate a MIDINFO data structure in DOS address-space }
- p := GlobalDOSAlloc (sizeof (MIDINFO));
- PMIDINFO (Ptr (LoWord (p), 0))^ := mid;
- if GetSetMid (drive, Ptr (HiWord (p), 0), $6901) then SetMid := True;
- GlobalDOSFree (LoWord (p));
- end;
-
- {----------------------------------------------------------------------------}
- { Name: GetSerialNumber }
- { Purpose: Get the serial number for a specified drive. }
- { If an error occurs, then 0 is returned as the serial number. }
- {----------------------------------------------------------------------------}
-
- function GetSerialNumber (drive: Byte): LongInt;
- var
- mid: MIDINFO;
- begin
- if GetMid (drive, mid) then GetSerialNumber := mid.SerialNum
- else GetSerialNumber := 0;
- end;
-
- {----------------------------------------------------------------------------}
- { Name: SetSerialNumber }
- { Purpose: Set the serial number for a specified drive. }
- { If no error, TRUE is returned as the function result. }
- {----------------------------------------------------------------------------}
-
- function SetSerialNumber (drive: Byte; serNum: LongInt): Bool;
- var
- mid: MIDINFO;
- begin
- SetSerialNumber := False;
- if GetMid (drive, mid) then
- begin
- mid.SerialNum := serNum;
- SetSerialNumber := SetMid (drive, mid);
- end;
- end;
-
- {----------------------------------------------------------------------------}
- { Name: GetCDDriveLetter }
- { Purpose: Return the drive letter of the CD-ROM drive (if any) }
- { If no CD is present, #0 is returned. }
- {----------------------------------------------------------------------------}
-
- function GetCDDriveLetter: Char; assembler;
- asm
- mov ax,$150B { do installation check for MSCDEX }
- mov bx,$ffff { preset the BX register }
- int $2F { see if MSCDEX is installed }
- inc bx { was BX register still -1 ? }
- jz @@1 { if so, there ain't no CD-ROM ! }
- xor bx,bx { clear BX register }
- mov ax,$1500 { request starting drive letter }
- int $2F { result in CX register }
- add cl,$41 { normalise into character 0->$41 }
- mov bx,cx { result in BX register }
- @@1: mov ax,bx { result in AX }
- mov ah,0 { clear the high byte }
- end;
-
- {----------------------------------------------------------------------------}
- { Name: RunningFromCD }
- { Purpose: True if this application is running from CD }
- {----------------------------------------------------------------------------}
-
- function RunningFromCD: Bool;
- var
- fName: array [0..255] of Char;
- begin
- GetModuleFileName (hInstance, fName, sizeof (fName));
- RunningFromCD := (fName [0] = GetCDDriveLetter);
- end;
-
- end.